/*
 * Part of knowledge engineering (ke) course work, 2010/11
 */
package se.bth.ke.firstfriend.dto;

import de.nixis.commons.web.base.model.UserBase;
import se.bth.ke.firstfriend.dto.todo.helper.Show;
import se.bth.ke.firstfriend.dto.todo.helper.Order;
import java.util.List;
import javax.persistence.EntityManager;
import se.bth.ke.firstfriend.model.dto.TodoInfo;

/**
 * Grants a view one the todos of the current logged in user.
 *
 * @author Markus Goetz
 */
public class TodoView {
    private static final int ITEMS_PER_PAGE = 20;

    private Order orderBy;
    private Show showBy;
    private int page;

    private final boolean sortOrderInverted;
    private List<TodoInfo> viewableItems;

    private EntityManager em;
    private UserBase user;
    
    public static int getItemsPerPage() {
        return ITEMS_PER_PAGE;
    }

    public TodoView(UserBase user, EntityManager em, String orderBy, String showBy, boolean sortOrderInverted, int page) {

        if (user == null) throw new IllegalArgumentException("user must not be null");
        if (orderBy == null) throw new IllegalArgumentException("orderBy must not be null");
        if (showBy == null) throw new IllegalArgumentException("showBy must not be null");

        try {
            this.user = user;
            this.em = em;
            
            this.orderBy = Order.fromString(orderBy);
            this.sortOrderInverted = sortOrderInverted;
            this.showBy = Show.fromString(showBy);
            this.page = validatePage(page);
            
            computeView();
        } catch (IllegalArgumentException e) {
            throw e;
        } catch (IllegalStateException e) {
            throw e;
        }
    }

    public List<TodoInfo> getViewableItems() {
        return viewableItems;
    }

    private int validatePage(int page) {
        if (page < 0) {
            throw new IllegalArgumentException("Page " + page + " not available");
        } else {
            try {
                long availableTodos = getAvailableTodosCount();

                if (availableTodos / ITEMS_PER_PAGE <= page) {
                    return page;
                }                
                throw new IllegalArgumentException("Page " + page + " not available");
            } catch (IllegalStateException e) {
                throw e;
            }
        }
    }

    private long getAvailableTodosCount() {
        if (user == null) {
            throw new IllegalStateException("Not logged in");
        }

        return (Long) em.createQuery("SELECT COUNT(t) FROM Todo t WHERE t.user = :user")
                           .setParameter("user", user)
                           .getSingleResult();
    }

    private void computeView() {
        List<TodoInfo> todos = orderBy.sort(showBy.filter(getAllTodos()), sortOrderInverted);

        int start = page * ITEMS_PER_PAGE;
        int end = start + ITEMS_PER_PAGE;

        if (todos.size() > ITEMS_PER_PAGE) {
            todos = todos.subList(start, end);
        }
        viewableItems = todos;
    }

    private List<TodoInfo> getAllTodos() {
        List<TodoInfo> infos = (List<TodoInfo>)
               em.createNamedQuery("Todo.getTodoInfosByUser")
                 .setParameter("user", user)
                 .getResultList();
        
        return infos;
    }

    /**
     * @return the orderBy
     */
    public String getOrderBy() {
        return orderBy.getOrderString();
    }

    /**
     * @return the showBy
     */
    public String getShowBy() {
        return showBy.getShowString();
    }

    /**
     * @return the sortOrderInverted flag
     */
    public boolean isSortOrderInverted() {
        return sortOrderInverted;
    }

    /**
     * @return the page
     */
    public int getPage() {
        return page;
    }
}
